#include "Material.h"

#include <gl/glew.h>

#include <gtc/type_ptr.hpp>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// -------- Default shader (simple Diffuse) ---------------------

const char* vertexBaseDiffuse =	"#version 150\n"
								"uniform mat4 ModelViewProjection;\n"
								"in vec4 Position;\n"
								"in vec3 Normal;\n"
								"invariant gl_Position;\n"
								"void main()\n"
								"{\n"
								"gl_Position = ModelViewProjection*Position; \n"
								"}\n";

const char* fragBaseDiffuse =	"#version 150\n"
								"out vec4 color0;\n"
								"void main()\n"
								"{\n"
								"color0 = vec4(0.0, 1.0, 0.0 ,1.0); \n"
								"}\n";


 
char *textFileRead(char *fn) {
 
    FILE *fp;
    char *content = NULL;
 
    int count=0;
 
    if (fn != NULL) {
        fp = fopen(fn,"rt");
 
        if (fp != NULL) {
 
      fseek(fp, 0, SEEK_END);
      count = ftell(fp);
      rewind(fp);
 
            if (count > 0) {
                content = (char *)malloc(sizeof(char) * (count+1));
                count = fread(content,sizeof(char),count,fp);
                content[count] = '\0';
            }
            fclose(fp);
        }
    }
    return content;
}

Material::Material(char* pVertex, char* pFragment)
{
	char *vs,*gs, *fs;
 
    // Create shader handlers
    int v = glCreateShader(GL_VERTEX_SHADER);
    int f = glCreateShader(GL_FRAGMENT_SHADER); 
 
    // Read source code from files
    /*vs = textFileRead("example.vert");
    gs = textFileRead("example.geom");
    fs = textFileRead("example.frag");*/
 
    // Set shader source
    glShaderSource(v, 1, &vertexBaseDiffuse,NULL);
	glShaderSource(f, 1, &fragBaseDiffuse,NULL);
 
    //free(vs);free(fs);
 
    // Compile all shaders
	glCompileShader(v);

    int status;
	glGetShaderiv(v, GL_COMPILE_STATUS, &status);

	char* pData;

	if(status != GL_TRUE)
	{
		int length;
		glGetShaderiv(v, GL_INFO_LOG_LENGTH, &length);
		char* pData = new char[length+10];

		glGetShaderInfoLog(v, length+10, &length, pData);
		delete pData;
	}
	
	glCompileShader(f);
	glGetShaderiv(f, GL_COMPILE_STATUS, &status);

	if(status != GL_TRUE)
	{
		int length;
		glGetShaderiv(f, GL_INFO_LOG_LENGTH, &length);
		char* pData = new char[length+10];

		glGetShaderInfoLog(f, length+10, &length, pData);
		delete pData;
	}
 
    // Create the program
    mProgram = glCreateProgram();
 
    // Attach shaders to program
    glAttachShader(mProgram,v);
    glAttachShader(mProgram,f);

	glBindAttribLocation(mProgram, 0, "Position");
	//glBindAttribLocation(mProgram, 1, "Normal");
	glBindFragDataLocation(mProgram, 0, "color0");
 
    // Link and set program to use
    glLinkProgram(mProgram);

	return;
}

void Material::bindShader()
{
	    glUseProgram(mProgram);
}

void Material::bindMatrix(char* pName, glm::mat4 pMat)
{
	int loc = glGetUniformLocation(mProgram, pName);

	glUniformMatrix4fv(loc, 1, 0, glm::value_ptr(pMat));
}